# -*- coding: utf-8 -*-
import os
import time
from datetime import datetime

from ding import DingApi
from ldap import LdapApi
from config import Config

cfg = Config()


class Updater(object):
    def __init__(self, appkey, appsecret, host, user, password, baseDn, blockedOu, use_ssl):
        """
        :param appkey: 钉钉的appkey
        :param appsecret: 钉钉的appsecret
        :param host: ldap的host
        :param user: ldap的管理员dn
        :param password: ldap的管理员password
        :param baseDn: search base
        :param blockedOu: 失效用户移入的OU
        """
        self.baseDn = baseDn
        self.ding = DingApi(appkey=appkey, appsecret=appsecret)
        self.ldap = LdapApi(host=host, user=user, password=password, baseDn=baseDn, use_ssl=use_ssl)
        self.blockedOu = blockedOu

    def update_ou(self):
        """
        将钉钉的部门更新到LDAP的ou
        :return:
        """
        # 0 添加blocked组，用来存放已离职的人
        self.ldap.create_ou(self.blockedOu)

        # 1 获取钉钉部门列表，并转化成LDAP可识别的OU列表
        ding_ou_list = []
        for x in self.ding.dept_dict.values():
            if x['ou']:
                ding_ou_list.append(x['ou'] + self.baseDn)
        ding_ou_list = sorted(ding_ou_list, key=lambda i: len(i))
        print("Ding ou list: ", ding_ou_list)

        # 2 获取现在LDAP中的OU列表
        ldap_ou_list = self.ldap.list_ou()
        print("Ldap ou list: ", ldap_ou_list)

        # 3 轮询钉钉ou列表，如果发现在ldap中不存在，则创建之
        add_ou_list = []
        for ding_ou in ding_ou_list:
            if ding_ou not in ldap_ou_list:
                self.ldap.create_ou(ding_ou)
                add_ou_list.append(ding_ou)
        # print("Add ou: {}".format(add_ou_list))

    def update_user(self):
        """
        将钉钉的用户更新到LDAP中，以钉钉的userid为唯一标识，Ldap中使用sn存放钉钉userid
        :return:
        """

        print("Ding dept dict: ", self.ding.dept_dict)

        # 1 获取钉钉用户字典，并附上ldap信息(key为钉钉userid，value为钉钉中的user对象)
        ding_user_dict = self.ding.get_all_user_dict()
        print("Ding user dict: ", ding_user_dict)

        # 2 获取ldap用户字典(key为用户的sn，value为ldap中的user对象)
        ldap_user_dict = self.ldap.get_all_user_dict()
        print("Ldap dept dict: ", ldap_user_dict)

        # 3 遍历每一个钉钉用户
        no_email_user = []
        for ding_uid, ding_user in ding_user_dict.items():
            top_dept_id = ding_user['department'][0]
            ding_ou = self.ding.dept_dict[top_dept_id]['ou'] + self.ldap.baseDn
            # 3 判断如果钉钉用户不存在LDAP中，则创建新用户
            if ding_uid not in ldap_user_dict.keys():
                print("创建用户: {}".format(ding_user['name']))
                ding_name = ding_user['name']
                ding_mobile = ding_user['mobile'] if ('mobile' in ding_user and ding_user['mobile']) else 0
                ding_email = ding_user['orgEmail'] if 'orgEmail' in ding_user else ' '
                if not ding_email:
                    no_email_user.append(ding_name)
                ding_title = ding_user['position'] if 'position' in ding_user else ' '
                ding_avatar = ding_user['avatar'] if ('avatar' in ding_user and ding_user['avatar']) else 'no photo'
                self.ldap.create_user(ding_name, ding_ou, ding_uid, ding_mobile, ding_email, ding_title, ding_avatar)

            # 4 如果钉钉用户在LDAP中，对比ou，如果不一致则移动
            else:
                ldap_dn = ldap_user_dict[ding_uid]['dn']
                ldap_rdn, ldap_ou = ldap_dn.split(',', 1)
                if ding_ou != ldap_ou:
                    print("移动用户: {}".format(ding_user['name']))
                    self.ldap.mv_dn(ldap_dn, ldap_rdn, ding_ou)
        print("no email user: {}".format(no_email_user))


        # 5 遍历每一个LDAP用户，如果不再dingding中，则删除密码并移入blockedOu
        for ldap_sn, ldap_user in ldap_user_dict.items():
            # print(ldap_user)
            # print(ldap_user['uid'])
            # print(cfg.IGNORE_UID)
            if ldap_user['uid'] in cfg.IGNORE_UID:
                print("- " + ldap_user['uid'] + " 在IGNORE_UID中，无需移动到Blocked组")
                continue   # 检测是否属于要忽略的UID
            if ldap_sn not in ding_user_dict.keys():
                ldap_dn = ldap_user['dn']
                ldap_rdn, _ = ldap_dn.split(',', 1)
                print("- 冻结用户: {}".format(ldap_dn))
                self.ldap.delete_password(ldap_dn)
                self.ldap.mv_dn(ldap_dn, ldap_rdn, self.blockedOu)


def timedTask():
    ding_appkey = cfg.DINGTALK_APPKEY
    ding_appsecret = cfg.DINGTALK_APPSECRET
    host = cfg.LDAP_HOST
    user = cfg.LDAP_USER
    passwd = cfg.LDAP_PASSWD
    search_base = cfg.LDAP_SEARCH_BASE
    blocked_ou = cfg.LDAP_BLOCKED_OU
    use_ssl = cfg.LDAP_USE_SSL
    sync_interval = cfg.SYNC_INTERVAL

    """
    定时执行任务
    :return:
    """
    while True:
        print("")
        print(datetime.now().strftime("%Y-%m-%d %H:%M:%S"), "==》 同步任务开始")
        updater = Updater(ding_appkey, ding_appsecret, host, user, passwd, search_base, blocked_ou, use_ssl)
        updater.update_ou()
        updater.update_user()
        print(datetime.now().strftime("%Y-%m-%d %H:%M:%S"), "==》 同步任务结束")
        time.sleep(sync_interval)


if __name__ == '__main__':
    timedTask()
